module Fileparser where
import System.IO
import Data.Char(toUpper)
import System.Environment
import Datatype
import VertexCover
---------------------------------------------------------------------
--this module process file 
--1.validate file provide error handling
--2. parser string 
--3.create Nodevalue date type ref Datatye.hs
--4. call VertexCover.hs to get output string


---------------------------------------------------------------------
--1, The following section start build the methods for parser String
---------------------------------------------------------------------
isgeq :: Int -> Int -> Bool
isgeq a b
		| a>=b = True
		| otherwise =False

parInt :: String -> Int
parInt a  
          | (read a )>= 0 = read a
          | otherwise = error "not right input K"


---takes string value to get each token and put into a list
split :: String -> Char -> [String]
split [] delim = [""]
split (c:cs) delim
   | c == delim = "" : rest
   | otherwise = (c : head rest) : tail rest
   where
       rest = split cs delim

---split file to be a string list by '\r\n' char 
linefile :: String -> [String]
linefile s = remove_nc (map remove_rc (split s '\n'))

---remove return char '\r'
remove_rc :: String ->String
remove_rc    "" = ""
remove_rc    (x:xs)
                | x=='\r' = ""++remove_rc xs
                | otherwise = [x]++remove_rc xs
                
---remove empty string---                
remove_nc :: [String]->[String]
remove_nc   []= []
remove_nc  (x:xs)
            |x=="" =remove_nc xs
            |otherwise = (x : remove_nc xs)

----findt K value from input file string 
findk :: String->Int
findk  s = parInt (head (linefile s))


---find size value from input file string
findsize :: String->Int
findsize s = parInt ( (linefile s) !! 1)


----the graph structure will be represent after second line
getgraphStr :: [String]->[String]
getgraphStr  s = drop 2 s



---- make a vertex entry from a line of file---
-----entry contains (key , value) key is vertex. value is vertex 's neghbours
make_entry :: String->(String ,[String])
make_entry  s  
             | iscontainEs(tail (trimcoma ( split s ' '))) = error "space indent error"
             |otherwise=( head (trimcoma ( split s ' ')) , tail (trimcoma ( split s ' ')))

---trim coma ---
trimcoma :: [String] -> [String]
trimcona    [] =error "the line can not be empty"
trimcoma   (x:s) 
             | (last x==',') && (length x >1) = (init x ): s
             | otherwise = error "first vertex should follow by a comma "



---is set comtain empty string--

iscontainEs :: [String] -> Bool
iscontainEs  [] = False
iscontainEs (x:xs) 
               | (x=="") = True
               | otherwise = False || iscontainEs xs



---------------------------------------------------------------------
--2. following section create graph from  input file string
---------------------------------------------------------------------
createGraph :: String -> Graph
createGraph  s = map make_entry ( getgraphStr (linefile s) )



--- create vertex set from a graph---
createVset :: Graph -> [String]
createVset      []  = []
createVset  ((key,value): g) = key : (createVset g)



validateGraph :: Graph ->[String]-> Bool
validateGraph     []  vs = True
validateGraph    ((k,v): g) vs 
                     |(iscontainStr k vs)&&(iscontainSet v vs) = True && validateGraph g vs  
                     | otherwise = False
                     
----check if graph 's all vertex all in vertex set.
isValidVertice :: Graph -> Bool
isValidVertice   g =  validateGraph g (createVset g)



-----does a set contain a string
iscontainStr :: String -> [String] -> Bool
iscontainStr   s [] = False
iscontainStr   s  (x:xs)
                 | s == x  =True
                 | otherwise = False || iscontainStr s xs

------does a set contain another set
iscontainSet :: [String ] -> [String] -> Bool
iscontainSet     [] s = True
iscontainSet     (x:xs) s
                    | iscontainStr x s =True && (iscontainSet xs s)
                    | otherwise = False
                    
                    
-----find a key's value from a given key and a graph
getValue :: String -> Graph -> [String]
getValue   key [] = []
getValue  key  ((k,v): g)
                      | key == k = v
                      |otherwise = getValue key g
                      

isNeghbour_contain_k :: String ->[String]->Graph->Bool
isNeghbour_contain_k    k [] g = True
isNeghbour_contain_k    k (x:xs) g 
                           | (iscontainStr k (getValue x g)) = True && isNeghbour_contain_k k xs g
                           | otherwise = False

--- check if vertex's neghours set  contains this vertex
validateAdj :: Graph -> Graph -> Bool
validateAdj     [] gp = True
validateAdj    ((k,v): g) gp
                     | (isNeghbour_contain_k k v gp) = True && validateAdj g gp
                     | otherwise =False

isGraphValid :: Graph -> Bool
isGraphValid     g = (validateAdj g g )&& (isValidVertice g) 


---check if K or Size constant value are valid-----
isValidconstant :: String->Bool
isValidconstant    file 
                    |not ((findsize file) >= (findk file) ) = error "K is not valid"
                    |not ( findsize file == ( length (createVset (createGraph file)))) = error " size is not valid"
                    |otherwise = True



----------------------------------------------------------------
---
--- 3. following section check if the file is valid 
---
------------------------------------------------------------------
isValidFile :: String -> Bool
isValidFile  f  
          | not (isValidconstant f ) = error "constant value K or Size not correct"
          | not (isGraphValid (createGraph f) )= error " graph is not valid"
          | otherwise =True
          
-----------------------------------------------------------------------
-- 4. process input file and call Vertexcover.hs method boundsearch to 
-- get outpurt result
---------------------------------------------------------------------

processFile :: String -> Nodevalue
processFile    file 
                | isValidFile file = ((createGraph file), (createVset (createGraph file)), [] , (findk file) , (findsize  file))                 
                | otherwise = error " unvalid input file "

setToStr :: [String]->String
setToStr    []=""
setToStr   (x:xs)= x++" "++setToStr xs

getOutPut :: Nodevalue -> String
getOutPut    a 
             | (length (boundsearch a))> 0 = show ( length (boundsearch a))
                                              ++"\r\n"++ (setToStr (boundsearch a))++"\r\n" 
             | otherwise = "No"


getOutputfile :: String -> String
getOutputfile     inputfile = getOutPut (processFile inputfile)


